﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using MvcShop;

namespace MvcShop.Models.Repositories
{
    /// <summary>
    /// 数据仓储基类
    /// </summary>
    /// <typeparam name="T">EF数据类</typeparam>
    public abstract class BaseRepositoryBase<T> : IRepository<T> where T : class
    {
        protected SouthShopEntities1 dataContext;

        private string _entitiesSetName;

        public BaseRepositoryBase()
        {
            this.dataContext = BaseRepository.CreateDataContext();
        }

        public BaseRepositoryBase(bool defaultEntitySetName)
        {
            this.dataContext = BaseRepository.CreateDataContext();
            if (defaultEntitySetName)
            {
                if (EntitySetName.EndsWith("y"))
                {
                    this._entitiesSetName = StringExtensions.RemoveChars(EntitySetName, EntitySetName.Length - 1) + "ies";
                }
                else
                {
                    this._entitiesSetName = EntitySetName + "s";
                }
            }
            else
            {
                throw new ArgumentNullException("entitiesSet");
            }

        }

        public BaseRepositoryBase(SouthShopEntities1 dataContext, string entitiesSetName)
        {
            if (dataContext == null)
                throw new ArgumentNullException("DataContext");
            if (String.IsNullOrEmpty(entitiesSetName))
                throw new ArgumentNullException("entitiesSet");

            this.dataContext = dataContext;
            this._entitiesSetName = entitiesSetName;
        }

        /// <summary>
        /// 实体类名称
        /// </summary>
        protected string EntitySetName
        {
            get { return typeof(T).Name; }
        }

        /// <summary>
        /// 实体集名称
        /// </summary>
        protected string EntitiesSetName
        {
            get { return _entitiesSetName; }
            set { _entitiesSetName = value; }
        }

        /// <summary>
        /// 实体集对象
        /// </summary>
        protected ObjectQuery<T> EntitySet
        {
            get { return dataContext.CreateQuery<T>("[" + EntitiesSetName + "]"); }
        }

        #region IRepository<T> 成员

        public virtual void Add(T entity)
        {
            dataContext.AddObject(EntitiesSetName, entity);
        }

        public virtual void Del(T entity)
        {
            dataContext.DeleteObject(entity);
        }

        public virtual void Del(ICriteria criteria) 
        {
            IEnumerable<T> query = EntitySet.Where(criteria.Expression, criteria.Parameters.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray());
            foreach (var item in query)
            {
                dataContext.DeleteObject(item);
            }
            dataContext.SaveChanges();
        }

        public virtual void Update(int entityId, T entity)
        {
            T t = Find(entityId);
            t = entity;
            dataContext.ApplyPropertyChanges(EntitiesSetName, t);
        }

        public IList<T> Find(ICriteria criteria)
        {
            if (criteria == null)
                throw new ArgumentNullException("criteria");
            var query = EntitySet.Where(criteria.Expression, criteria.Parameters.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray());
            //var str = query.ToTraceString();
            return ToList(query);
        }

        public IList<T> FindAll()
        {
            return ToList(EntitySet);
        }

        public IList<T> Find(ICriteria criteria, int page, int pageSize, Order orderExpr)
        {
            if (criteria == null || orderExpr == null)
                throw new ArgumentNullException("criteria");
            var query = EntitySet.Where(criteria.Expression, criteria.Parameters.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray());


            return ToList(orderExpr.OrderFrom<T>(query).Skip((page - 1) * pageSize).Take(pageSize));
        }

        public IQueryable<T> FindQueryable(ICriteria criteria, int page, int pageSize, Order orderExpr)
        {
            if (criteria == null || orderExpr == null)
                throw new ArgumentNullException("criteria");
            var query = EntitySet.Where(criteria.Expression, criteria.Parameters.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray());

            return orderExpr.OrderFrom<T>(query).Skip((page - 1) * pageSize).Take(pageSize);
        }

        public int Count(ICriteria criteria)
        {
            if (criteria == null)
                throw new ArgumentNullException("criteria");
            return EntitySet.Where(criteria.Expression, criteria.Parameters.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray()).Count();
        }

        public void SaveChanges()
        {
            dataContext.SaveChanges();
        }

        public void AcceptAllChanges()
        {
            dataContext.AcceptAllChanges();
        }

        public virtual T Find(int entityId)
        {
            return Find(new EqualParameterCriteria(EntitySetName + "Id", entityId)).FirstOrDefault();
        }

        protected virtual IList<T> ToList(IQueryable<T> query)
        {
            try
            {
                return query.AsEnumerable().Select(c => c).Cast<T>().ToList();
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }

        #endregion
    }
}
